package com.dcivision.dms.core;

import java.io.File;
import java.io.InputStream;
import java.sql.Connection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.dcivision.dms.DmsErrorConstant;
import com.dcivision.dms.DmsOperationConstant;
import com.dcivision.dms.bean.DmsContent;
import com.dcivision.dms.bean.DmsDocument;
import com.dcivision.dms.bean.DmsLocMaster;
import com.dcivision.dms.dao.DmsContentDAObject;
import com.dcivision.dms.dao.DmsLocMasterDAObject;
import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemParameterConstant;
import com.dcivision.framework.SystemParameterFactory;

public class DmsContentManager {

  public static final String REVISION = "$Revision: 1.1 $";

  protected Log log = LogFactory.getLog(this.getClass().getName());
  private SessionContainer sessionContainer = null;
  private Connection conn=null;  
  
  
  /**
   *  Constructor - Creates a new instance of DmsContentManager
   */
  public DmsContentManager(SessionContainer sessionContainer, Connection conn) {
    this.sessionContainer = sessionContainer;
    this.conn = conn;
   }

  /**
   *  Release - To release the variable in instance of DmsContentManager
   */
  public void release () {
    this.sessionContainer = null;
    this.conn = null;
  }
  
  
  /**
   * write DmsDocument content by contentStoreHandler
   * 
   * <PRE>
   * 
   * This method is write document content to store folder ,the contentStoreHandler is get instance by
   * SystemParameterConstant.DMS_CONTENT_STORE_CLASS
   * 
   * The write process include : 
   * 1. Get the local master segment number,the segment number is the max fill 
   * 2. Get contentStoreHandler instance
   * 3. Set handler need parameter
   * 4. Write content
   * 5. Process segment
   * </PRE>
   * 
   * @param dmsDocument
   *          the handler document
   * @param convertedName
   *          is converted name,i.e. physic file name
   * @return DmsContentStoreHandler the handler
   * @throws ApplicationException,ContentStoreException
   */
  public DmsContentStoreHandler writeDmsDocumentStoreContent(DmsDocument dmsDocument, String convertedName, InputStream data)
      throws ApplicationException, ContentStoreException {
    DmsContentStoreHandler contentStoreHandler = null;
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    String foldersDir = docRetrievalManager.getFoldersDirectories(dmsDocument).toString();
    RootRetrievalManager rootRetrievalManager = new RootRetrievalManager(sessionContainer, conn);
    DmsLocMaster locMaster = rootRetrievalManager.getTargetLocMasterByDocument(dmsDocument);
    DmsLocMasterDAObject locMasterDAO = new DmsLocMasterDAObject(sessionContainer, conn);
    Integer rolloverLimit = SystemParameterFactory.getSystemParameterInteger(SystemParameterConstant.DMS_FILE_ROLLOVER_LIMIT);
    
    //1. get the local master segment number,the segment number is the max fill    
    // segment number at the folder name
    Integer locMasterSegmentNumber = locMaster.getSegmentNO();
    
    //2. Get contentStoreHandler instance
    try {
      contentStoreHandler = (DmsContentStoreHandler) Class.forName(
          SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_CONTENT_STORE_CLASS))
          .newInstance();
    } catch (Exception e) {
      log.error("Content Store Handler class not found.", e);
      throw new ApplicationException(DmsErrorConstant.NAME_CONVERTOR_CLASS_NOT_FOUND);
    }
    //3. Set handler need parameter
    
    // if rolloverLimit.intValue() > 0 then  set the current local master segment number
    if (rolloverLimit.intValue() > 0&&locMasterSegmentNumber!=null){      
      contentStoreHandler.setProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY, locMasterSegmentNumber);
    }
    // set the converted name,i.e. physic file name
    contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_NAME_PROPERTY, convertedName);
    // set the physicy file store foldr
    contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_PHYSICAL_PATH, foldersDir);
    // set the file content
    contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_CONTENT_PROPERTY, data);
    // set the file extension
    if (dmsDocument.getDocumentName().lastIndexOf(".") != -1) {
      if (dmsDocument.getDocumentName().lastIndexOf(".") + 1 < dmsDocument.getDocumentName().length()) {
        contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_EXTENSION_PROPERTY, dmsDocument
            .getDocumentName().substring(dmsDocument.getDocumentName().lastIndexOf(".") + 1,
                dmsDocument.getDocumentName().length()));
      }
    } else {
      contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_EXTENSION_PROPERTY, "BIN");
    }
    // set file size
    if(dmsDocument.getItemSize()!=null)
      contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_SIZE_PROPERTY, dmsDocument.getItemSize());
    
    //4. write content
    log.info("Start content write");
    contentStoreHandler.write();
    log.info("Finish content write");
    
    // 5. if file size more then rolloverLimit,the newSegmentNumber will
    // +1,then
    // need save the change at local master table
    if (rolloverLimit.intValue() > 0) {
      Integer newSegmentNumber = (Integer) contentStoreHandler
          .getProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY);
      if (locMasterSegmentNumber==null || locMasterSegmentNumber.intValue() != newSegmentNumber.intValue()) {
        locMaster.setSegmentNO(newSegmentNumber);
        locMasterDAO.updateObject(locMaster);
      }
    }
    return contentStoreHandler;
  }    
  
  /**
   * write DmsDocument content by contentStoreHandler
   * 
   * <PRE>
   * 
   * This method is write document content to store folder ,the contentStoreHandler is get instance by
   * SystemParameterConstant.DMS_CONTENT_STORE_CLASS
   * 
   * The write process include : 
   * 1. Get the local master segment number,the segment number is the max fill 
   * 2. Get contentStoreHandler instance
   * 3. Set handler need parameter
   * 4. Write content
   * 5. Process segment
   * </PRE>
   * 
   * @param dmsDocument
   *          the handler document
   * @param convertedName
   *          is converted name,i.e. physic file name
   * @return DmsContentStoreHandler the handler
   * @throws ApplicationException,ContentStoreException
   */
  public DmsContentStoreHandler writeDmsDocumentStoreContent(DmsDocument dmsDocument, DmsLocMaster locMaster, String convertedName, InputStream data)
      throws ApplicationException, ContentStoreException {
    DmsContentStoreHandler contentStoreHandler = null;
//    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    String foldersDir = locMaster.getLocPath()+"/";
//    RootRetrievalManager rootRetrievalManager = new RootRetrievalManager(sessionContainer, conn);
    
    DmsLocMasterDAObject locMasterDAO = new DmsLocMasterDAObject(sessionContainer, conn);
    Integer rolloverLimit = SystemParameterFactory.getSystemParameterInteger(SystemParameterConstant.DMS_FILE_ROLLOVER_LIMIT);
    
    //1. get the local master segment number,the segment number is the max fill    
    // segment number at the folder name
    Integer locMasterSegmentNumber = locMaster.getSegmentNO();
    
    //2. Get contentStoreHandler instance
    try {
      contentStoreHandler = (DmsContentStoreHandler) Class.forName(
          SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_CONTENT_STORE_CLASS))
          .newInstance();
    } catch (Exception e) {
      log.error("Content Store Handler class not found.", e);
      throw new ApplicationException(DmsErrorConstant.NAME_CONVERTOR_CLASS_NOT_FOUND);
    }
    //3. Set handler need parameter
    
    // if rolloverLimit.intValue() > 0 then  set the current local master segment number
    if (rolloverLimit.intValue() > 0){
      contentStoreHandler.setProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY, locMasterSegmentNumber);
    }
    // set the converted name,i.e. physic file name
    contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_NAME_PROPERTY, convertedName);
    // set the physicy file store foldr
    contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_PHYSICAL_PATH, foldersDir);
    // set the file content
    contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_CONTENT_PROPERTY, data);
    // set the file extension
    if (dmsDocument.getDocumentName().lastIndexOf(".") != -1) {
      if (dmsDocument.getDocumentName().lastIndexOf(".") + 1 < dmsDocument.getDocumentName().length()) {
        contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_EXTENSION_PROPERTY, dmsDocument
            .getDocumentName().substring(dmsDocument.getDocumentName().lastIndexOf(".") + 1,
                dmsDocument.getDocumentName().length()));
      }
    } else {
      contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_EXTENSION_PROPERTY, "BIN");
    }
    // set file size
    contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_SIZE_PROPERTY, dmsDocument.getItemSize());
    
    //4. write content
    log.info("Start content write");
    contentStoreHandler.write();
    log.info("Finish content write");
    
    // 5. if file size more then rolloverLimit,the newSegmentNumber will
    // +1,then
    // need save the change at local master table
    if (rolloverLimit.intValue() > 0) {
      Integer newSegmentNumber = (Integer) contentStoreHandler
          .getProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY);
      if (locMasterSegmentNumber.intValue() != newSegmentNumber.intValue()) {
        locMaster.setSegmentNO(newSegmentNumber);
        locMasterDAO.updateObject(locMaster);
      }
    }
    return contentStoreHandler;
  }      
  
  /**
   * Read DmsDocument content by contentStoreHandler
   * 
   * <PRE>
   * 
   * This method is read document content ,the contentStoreHandler is get instance by
   * SystemParameterConstant.DMS_CONTENT_STORE_CLASS
   * 
   * The read process include : 
   * 1. Get contentStoreHandler instance 
   * 2. Set handler need parameter
   * 3. read content
   * </PRE>
   * 
   * @param dmsDocument
   *          the handler document
   * @param docContent
   *          is relation docContent
   * @return InputStream is the document content
   * @throws ApplicationException,ContentStoreException
   */  
  public InputStream  readDmsDocumentStoreContent(DmsDocument dmsDocument,DmsContent docContent) throws ApplicationException,ContentStoreException {
    InputStream dataStream = null;
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);    
    String foldersDir = docRetrievalManager.getFoldersDirectories(dmsDocument).toString();
    DmsContentStoreHandler contentStoreHandler = null;
    
    //1. Get contentStoreHandler instance    
    try {
      contentStoreHandler = (DmsContentStoreHandler)Class.forName(SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_CONTENT_STORE_CLASS)).newInstance();
    } catch (Exception e) {
      throw new ApplicationException(DmsErrorConstant.NAME_CONVERTOR_CLASS_NOT_FOUND);
    }
    //2. Set handler need parameter
    // set the converted name,i.e. physic file name
    contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_NAME_PROPERTY, docContent.getConvertedName());
    // set the current local master segment number
    if(docContent.getSegmentNO()!=null)
      contentStoreHandler.setProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY, docContent.getSegmentNO());
    // set the physicy file store foldr
    contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_PHYSICAL_PATH, foldersDir);
    
    //3. read content
    dataStream = contentStoreHandler.readStream();    
    
    return dataStream;
  }  
  
  
  
  /**
   * Delete DmsDocument content by contentStoreHandler
   * 
   * <PRE>
   * 
   * This method is delete document content ,the contentStoreHandler is get instance by
   * SystemParameterConstant.DMS_CONTENT_STORE_CLASS
   * 
   * The delete process include : 
   * 1. Get contentStoreHandler instance 
   * 2. Set handler need parameter
   * 3. delete content
   * </PRE>
   * 
   * @param dmsDocument
   *          the handler document
   * @param docContent
   *          is relation docContent
   * @return void
   * @throws ApplicationException,ContentStoreException
   */    
  public void deleteDmsDocumentStoreContent(DmsDocument dmsDocument,DmsContent docContent) throws ApplicationException,ContentStoreException {
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);
    DmsContentDAObject dmsContentDAO = new DmsContentDAObject(sessionContainer, conn);    
    String foldersDir = docRetrievalManager.getFoldersDirectories(dmsDocument).toString();
    RootRetrievalManager rootRetrievalManager = new RootRetrievalManager(sessionContainer, conn);
    DmsLocMaster locMaster = rootRetrievalManager.getTargetLocMasterByDocument(dmsDocument);    
    DmsContentStoreHandler contentStoreHandler = null;
    
    // if the physical file is shared by other document then can't delete it
    if (dmsContentDAO.checkHasListByConvertedNameUnderSameLoc(docContent.getConvertedName(), locMaster.getID())) {
        return ;
    }
    
    //1. Get contentStoreHandler instance
    try {
      contentStoreHandler = (DmsContentStoreHandler)Class.forName(SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_CONTENT_STORE_CLASS)).newInstance();
    } catch (Exception e) {
      throw new ApplicationException(DmsErrorConstant.NAME_CONVERTOR_CLASS_NOT_FOUND);
    }
    //2. Set handler need parameter
    // set the converted name,i.e. physic file name
    contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_NAME_PROPERTY, docContent.getConvertedName());
    // set the current local master segment number
    if(docContent.getSegmentNO()!=null)
      contentStoreHandler.setProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY, docContent.getSegmentNO());
    // set the physicy file store foldr
    contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_PHYSICAL_PATH, foldersDir);
    
    //3. delete content
    contentStoreHandler.delete();    
  }
  
  /**
   * Rename DmsDocument content by contentStoreHandler
   * 
   * <PRE>
   * 
   * This method is rename document content ,the contentStoreHandler is get instance by
   * SystemParameterConstant.DMS_CONTENT_STORE_CLASS
   * 
   * The rename process include : 
   * 1. Get contentStoreHandler instance 
   * 2. Set handler need parameter
   * 3. Rename content
   * </PRE>
   * 
   * @param dmsDocument
   *          the handler document
   * @param docContent
   *          is relation docContent
   * @return void
   * @throws ApplicationException,ContentStoreException
   */
  public void renameDmsDocumentStoreContent(DmsDocument dmsDocument,DmsContent docContent,String newConvertedName) throws ApplicationException,ContentStoreException {
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);    
    String foldersDir = docRetrievalManager.getFoldersDirectories(dmsDocument).toString();
    DmsContentStoreHandler contentStoreHandler = null;
    // if converted name is same ,not need use rename
    if(docContent.getConvertedName().equals(newConvertedName)){
      return;
    }
    //1. Get contentStoreHandler instance
    try {
      contentStoreHandler = (DmsContentStoreHandler)Class.forName(SystemParameterFactory.getSystemParameter(SystemParameterConstant.DMS_CONTENT_STORE_CLASS)).newInstance();
    } catch (Exception e) {
      throw new ApplicationException(DmsErrorConstant.NAME_CONVERTOR_CLASS_NOT_FOUND);
    }
    //2. Set handler need parameter
    // set the converted name,i.e. physic file name
    contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_NAME_PROPERTY, docContent.getConvertedName());
    // set the current local master segment number
    if(docContent.getSegmentNO()!=null)
      contentStoreHandler.setProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY, docContent.getSegmentNO());
    // set the physicy file store foldr
    contentStoreHandler.setProperty(DmsContentStoreHandler.FILE_PHYSICAL_PATH, foldersDir);
    // set the physicy file store foldr
    contentStoreHandler.setProperty(DmsContentStoreHandler.NEW_FILE_NAME, newConvertedName);
    
    //3. rename content
    contentStoreHandler.rename();    
  }
    
  public String getDmsDocumentStoreFilePysicalPath(DmsDocument dmsDocument,DmsContent docContent) throws ApplicationException,ContentStoreException {
    String physicalPath = "";
    DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(sessionContainer, conn);    
    String directory = docRetrievalManager.getFoldersDirectories(dmsDocument).toString();
    Integer segmentNumber =docContent.getSegmentNO();

    if (directory.charAt(directory.length() - 1) != File.separatorChar
        && directory.charAt(directory.length() - 1) != '/') {
      directory = directory + System.getProperty("file.separator");
    }

    if (segmentNumber != null){
      String segmentPath = DmsOperationConstant.documentPath +"/" + DmsOperationConstant.segment +  segmentNumber + "/";
      directory += segmentPath;
    }    
    physicalPath = directory + docContent.getConvertedName();
    
    return physicalPath ;
  }
    
}
